﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Threading;
using System.Xml.Linq;
using Microsoft.Xrm.Sdk.Metadata;
using System.IO;

namespace VisualRibbonEditor
{
	public partial class OpenEntityDialog : UserControl, IDialog
	{
		//This array contains all of the system entities that use the ribbon.
		private string[] entitiesWithRibbons = 
		{"account", "activitymimeattachment","activitypointer","appointment",
			"bulkoperation","campaign","campaignactivity","campaignresponse",
			"competitor","connection","contact","contract","contractdetail",
			"customeraddress","discount","discounttype","email","fax","goal",
			"importfile","incident","invoice","invoicedetail","kbarticle",
			"kbarticlecomment","lead","letter","list","listmember", "metric",
			"opportunity","opportunityproduct","phonecall","pricelevel","product",
			"productpricelevel","queueitem","quote","quotedetail",
			"recurringappointmentmaster","report","salesliterature","salesorder",
			"salesorderdetail","service","serviceappointment","sharepointdocumentlocation",
			"sharepointsite","systemuser","task","team","territory","uom","uomschedule",
			"userquery"};

		public OpenEntityDialog()
		{
			MainWindow.CurrentMainPage.ShowConnectionStatus();
			InitializeComponent();

			if (!LoadEntitiesFromFile())
			{
				RetrieveEntities();
			}
		}

		private bool LoadEntitiesFromFile()
		{
			string fileName = GetFileName();
			if (File.Exists(fileName))
			{
				string data = File.ReadAllText(fileName);
				XElement x = XElement.Parse(data);

				int index = 0;
				int selectedEntityIndex = index;

				foreach (XElement el in x.Elements())
				{
					ComboBoxItem cbi = new ComboBoxItem();
					cbi.Content = el.AttributeValue("DisplayName");
					cbi.Tag = el.AttributeValue("LogicalName");
					index = EntityPicker.Items.Add(cbi);
					if (cbi.Tag.ToString() == Connection.CurrentConnection.EntityName) selectedEntityIndex = index;
				}

				EntityPicker.SelectedIndex = selectedEntityIndex;

				return true;
			}
			else
			{
				return false;
			}
		}

		private void SaveEntitiesToFile()
		{
			XElement x = new System.Xml.Linq.XElement("Entities");
			foreach (ComboBoxItem cbi in EntityPicker.Items)
			{
				XElement e = new System.Xml.Linq.XElement("Entity");
				e.SetAttributeValue("DisplayName", cbi.Content.ToString());
				e.SetAttributeValue("LogicalName", cbi.Tag.ToString());
				x.Add(e);
			}
			File.WriteAllText(GetFileName(), x.ToString());
		}

		private string GetFileName()
		{
			string validChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
			System.Text.StringBuilder sb = new System.Text.StringBuilder("Entities_");
			foreach (char c in Connection.CurrentConnection.ServerUrl)
			{
				if (validChars.Contains(c))
				{
					sb.Append(c);
				}
			}
			sb.Append("_");
			foreach (char c in Connection.CurrentConnection.OrgName)
			{
				if (validChars.Contains(c))
				{
					sb.Append(c);
				}
			}
			sb.Append(".xml");
			return sb.ToString();
		}

		private void RetrieveEntities()
		{
			//add a "Please wait" to the picker
			MetadataCache.AllEntitiesRetrieved = false;
			EntityPicker.Items.Clear();
			TextBlock tb = new TextBlock();
			tb.Text = "Retrieving entities, please wait...";
			tb.FontStyle = FontStyles.Italic;
			ComboBoxItem pleaseWait = new ComboBoxItem();
			pleaseWait.Content = tb;
			EntityPicker.Items.Add(pleaseWait);
			EntityPicker.SelectedIndex = 0;
			EntityPicker.IsEnabled = false;
			OKButton.IsEnabled = false;
			if (!Connection.CurrentConnection.IsConnected)
			{
				MainWindow.CurrentMainPage.ShowConnectionStatus("Connecting to {OrgName} on {ServerHostName} {ServerType}", Connection.CurrentConnection);
				// Test connection. OrganizationId is not loaded here
				Connection.CurrentConnection.TestConnection(false, true, (passed, errorDescription) =>
				{
					if (!passed)
					{
						string errorMessage = "Failed to connect to CRM.";
						if (!String.IsNullOrEmpty(errorDescription)) errorMessage += (Environment.NewLine + errorDescription);
						MessageBox.Show(errorMessage);
						return;
					}
					else
					{
						MainWindow.CurrentMainPage.ShowConnectionStatus("Connected to {OrgName} on {ServerHostName} {ServerType}", Connection.CurrentConnection);
					}
				});
			}
			MetadataCache.GetAllEntityNames(EntitiesLoaded);
		}

		private void EntitiesLoaded(EntityMetadata[] entities)
		{
			EntityPicker.Items.Clear();

			ComboBoxItem appItem = new ComboBoxItem();
			appItem.Content = "Application Ribbons";
			appItem.Tag = "application";
			int index = EntityPicker.Items.Add(appItem);

			int selectedEntityIndex = index;

			foreach( EntityMetadata d in entities
				.Where( (x) => (entitiesWithRibbons.Contains(x.LogicalName) || x.IsCustomEntity.Value)
					&& x.DisplayName != null && x.DisplayName.UserLocalizedLabel != null && x.IsCustomizable.Value)
				.OrderBy( x => x.DisplayName.UserLocalizedLabel.Label))
			{
				ComboBoxItem cbi = new ComboBoxItem();
				cbi.Content = d.DisplayName.UserLocalizedLabel.Label;
				cbi.Tag = d.LogicalName;
				index = EntityPicker.Items.Add(cbi);
				if (d.LogicalName == Connection.CurrentConnection.EntityName) selectedEntityIndex = index;
			}

			EntityPicker.SelectedIndex = selectedEntityIndex;

			SaveEntitiesToFile();
			EntityPicker.IsEnabled = true;
			OKButton.IsEnabled = true;
		}

		private void OKButton_Click(object sender, RoutedEventArgs e)
		{
			ComboBoxItem cbi = (ComboBoxItem) EntityPicker.SelectedValue;
 
			if (cbi != null && DialogClosed != null)
			{
				DialogClosed(cbi.Tag.ToString()); //close with the entityname as return param.
			}
		}
		 
		/// <summary>
		/// user clicked the cancel button. Call DialogClose event with NULL to indicate a cancel.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void CancelButton_Click(object sender, RoutedEventArgs e)
		{
			if (DialogClosed != null)
			{
				DialogClosed(null);
			}
		}

		public event CloseDialogHandler DialogClosed;

		private void RefreshLink_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
		{
			RetrieveEntities();
		}

		private void RefreshLink_KeyDown(object sender, KeyEventArgs e)
		{
			if (e.Key == Key.Enter || e.Key == Key.Space)
			{
				RetrieveEntities();
			}
		}

		private void OpenEntityDialog_KeyUp(object sender, KeyEventArgs e)
		{
			switch (e.Key) //
			{
				// ENTER
				case Key.Enter:
					// Check if key is not comming from RefreshLink control
					if (e.OriginalSource != RefreshLink) OKButton_Click(sender, new RoutedEventArgs());
					break;
				// ESC
				case Key.Escape:
					if (DialogClosed != null) DialogClosed(null);
					break;
				default:
					break;
			}
		}
	}

}
